/**
 * 
 */
package game.kill.biz.impl;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;

import game.kill.biz.MessageSendBiz;
import game.kill.biz.StepEngineBiz;
import game.kill.enums.GameRecordTypeEnum;
import game.kill.enums.GameStepEnum;
import game.kill.enums.PlayerActionEnum;
import game.kill.enums.PlayerRoleEnum;
import game.kill.enums.PlayerStatusEnum;
import game.kill.enums.RoomStatusEnum;
import game.kill.model.GameRecord;
import game.kill.model.GameRoomInfo;
import game.kill.model.Room;
import game.kill.model.RoomUser;
import game.kill.model.StepActionRecord;
import game.kill.service.GameRecordService;
import game.kill.service.RoomService;
import game.kill.service.RoomUserService;
import game.kill.service.StepActionRecordService;
import lombok.extern.slf4j.Slf4j;

/**
 * @author macbook
 *
 */

@Slf4j
@Service("stepEngineBiz")
public class StepEngineBizImpl implements StepEngineBiz{

	private static final Logger logger = LoggerFactory.getLogger(StepEngineBizImpl.class);
	
	private ScheduledExecutorService scheduledExecutorService;
	
	private static int poolSize = 2;
	
	private static boolean daemon = Boolean.TRUE;
	
	private Map<Long,ScheduledFuture<?>> futureMap = new HashMap<Long, ScheduledFuture<?>>();
	
	//private Map<Long,GameRoomInfo> gameRoomInfoMap = new LinkedHashMap<Long,GameRoomInfo>();

	@Resource
	private StepActionRecordService stepActionService;
	
	@Resource
	private RoomUserService roomUserService;
	
	@Resource
	private GameRecordService gameRecordService;
	
	@Resource
	private RoomService roomService;
	
	@Resource
	private MessageSendBiz messageSendBiz;
	
	public void init(){
		
	}
	/**
	 * 初始化 scheduledExecutorService
	 */
	private void initScheduledExecutorService(){
		logger.info("daemon:{},poolSize:{}",daemon,poolSize);
		scheduledExecutorService =  Executors.newScheduledThreadPool(poolSize,new ThreadFactory() {

			@Override
			public Thread newThread(Runnable arg0) {
				Thread thread = Executors.defaultThreadFactory().newThread(arg0);
				//设置守护线程
				thread.setDaemon(daemon);
				return thread;
			}
		});
	}
	
	public void addGameSchedule(GameRoomInfo roomInfo,int delay){
		Long roomId = roomInfo.getRoom().getId();
		if(scheduledExecutorService == null){
			initScheduledExecutorService();
		}
		if(futureMap.containsKey(roomId)){
			return;
		}
		ScheduledFuture<?> scheduledFuture =  scheduledExecutorService.schedule(new Runnable() {
			@Override
			public void run() {
				
				logger.info("add alive room in stepEngine with roomId:{}",roomId);
				doGameStep(roomInfo);
			}
			
		},delay,TimeUnit.SECONDS);
		
		futureMap.put(roomId,scheduledFuture);
		//gameRoomInfoMap.put(roomId, roomInfo);
	}
	
	@Override
	public void doGameStep(GameRoomInfo gameRoomInfo) {
		log.info("doGameStep start,gameRoomInfo={}",gameRoomInfo);
		Room room = gameRoomInfo.getRoom();
		String step = room.getStep();
		if(GameStepEnum.dark_work.name().equals(step)){
			Integer killTarget = getCurrentRoomStepAgreedTarget(room,PlayerActionEnum.kill);
			
			Integer checkTarget = getCurrentRoomStepAgreedTarget(room,PlayerActionEnum.check);
			
			if(killTarget!=null){
				RoomUser killedPlayer = gameRoomInfo.getRoomUserMap().get(killTarget);
				killedPlayer.setStatus(PlayerStatusEnum.dead.getCode());
				killedPlayer.setDeadRound(room.getRound());
				
				RoomUser updateRoomUser = new RoomUser();
				updateRoomUser.setId(killedPlayer.getId());
				updateRoomUser.setDeadRound(room.getRound());
				updateRoomUser.setStatus(PlayerStatusEnum.dead.getCode());
				roomUserService.updatePlayerById(updateRoomUser);
				
				GameRecord gameRecord = new GameRecord(); 
				gameRecord.setRoomId(room.getId());
				gameRecord.setRoundNum(room.getRound());
				gameRecord.setStep(room.getStep());
				gameRecord.setType(GameRecordTypeEnum.kill_dead.getCode());
				gameRecord.setTarget(killTarget);
				gameRecord.setInfo(killTarget+"号玩家被杀");
				gameRecordService.save(gameRecord);
			}
			
			if(checkTarget!=null){
				RoomUser checkedPlayer = gameRoomInfo.getRoomUserMap().get(checkTarget);
				
				boolean result = false;
				if(checkedPlayer.getRoleId() == PlayerRoleEnum.killer.getCode()){
					result = true;
				}
				
				GameRecord gameRecord = new GameRecord(); 
				gameRecord.setRoomId(room.getId());
				gameRecord.setRoundNum(room.getRound());
				gameRecord.setStep(room.getStep());
				gameRecord.setType(GameRecordTypeEnum.check.getCode());
				gameRecord.setTarget(checkTarget);
				gameRecord.setInfo(checkTarget+"号玩家被验,法官提示是否是杀手:"+ (result?"是":"不是"));
				gameRecordService.save(gameRecord);
			}
			
		}
		else if(GameStepEnum.free_speak.name().equals(step)){
			
		}
		
		else if(GameStepEnum.vote.name().equals(step)){
			//Integer voteTarget = getCurrentRoomStepAgreedTarget(room,PlayerActionEnum.vote);
			List<Map.Entry<Integer,Integer>> voteTargetTopList = getCurrentRoomStepAgreedTopTarget(room,PlayerActionEnum.vote);
			if(voteTargetTopList!=null&&voteTargetTopList.size()==1){
				Integer voteTarget = voteTargetTopList.get(0).getKey();
				RoomUser votedPlayer = gameRoomInfo.getRoomUserMap().get(voteTarget);
				votedPlayer.setStatus(PlayerStatusEnum.dead.getCode());
				votedPlayer.setDeadRound(room.getRound());
				
				
				RoomUser updateRoomUser = new RoomUser();
				updateRoomUser.setId(votedPlayer.getId());
				updateRoomUser.setDeadRound(room.getRound());
				updateRoomUser.setStatus(PlayerStatusEnum.dead.getCode());
				roomUserService.updatePlayerById(updateRoomUser);
				GameRecord gameRecord = new GameRecord(); 
				gameRecord.setRoomId(room.getId());
				gameRecord.setRoundNum(room.getRound());
				gameRecord.setStep(room.getStep());
				gameRecord.setType(GameRecordTypeEnum.voted_dead.getCode());
				gameRecord.setTarget(voteTarget);
				gameRecord.setInfo(voteTarget+"号玩家被票死");
				gameRecordService.save(gameRecord);
				this.messageSendBiz.sendMsgByGameRecord(gameRecord, gameRoomInfo);
			}else if(voteTargetTopList!=null&& voteTargetTopList.size()> 1){
				doPalayerVotedResult(gameRoomInfo,voteTargetTopList);
			}
			
		}
		
		doNextStep(gameRoomInfo);
		
	}
	
	private void doPalayerVotedResult(GameRoomInfo gameRoomInfo,List<Map.Entry<Integer,Integer>> voteTargetTopList){
		Room room = gameRoomInfo.getRoom();
		for(Map.Entry<Integer,Integer> targetTop:voteTargetTopList){
			Integer voteTarget = targetTop.getKey();
			RoomUser votedPlayer = gameRoomInfo.getRoomUserMap().get(voteTarget);
			votedPlayer.setStatus(PlayerStatusEnum.dead.getCode());
			votedPlayer.setDeadRound(room.getRound());
			
			
			RoomUser updateRoomUser = new RoomUser();
			updateRoomUser.setId(votedPlayer.getId());
			updateRoomUser.setDeadRound(room.getRound());
			updateRoomUser.setStatus(PlayerStatusEnum.dead.getCode());
			roomUserService.updatePlayerById(updateRoomUser);
			GameRecord gameRecord = new GameRecord(); 
			gameRecord.setRoomId(room.getId());
			gameRecord.setRoundNum(room.getRound());
			gameRecord.setStep(room.getStep());
			gameRecord.setType(GameRecordTypeEnum.voted_dead.getCode());
			gameRecord.setTarget(voteTarget);
			gameRecord.setInfo(voteTarget+"号玩家被票死");
			gameRecordService.save(gameRecord);
			this.messageSendBiz.sendMsgByGameRecord(gameRecord, gameRoomInfo);
		}
	}
	
	private void doNextStep(GameRoomInfo gameRoomInfo){
		
		log.info("doNextStep start,gameRoomInfo={}",gameRoomInfo);
		Room room = gameRoomInfo.getRoom();
		String step = room.getStep();
		GameStepEnum stepEnum = GameStepEnum.getByName(step);
		boolean isGameOver = gameRoomInfo.isGameOver();
		if(isGameOver){
			room.setStatus(RoomStatusEnum.ending.getCode());
			roomService.updateStatus(room);
			return;
		}else {
			if(GameStepEnum.dark_work == stepEnum){
				room.setStep(GameStepEnum.free_speak.name());
			}else if(GameStepEnum.free_speak == stepEnum){
				room.setStep(GameStepEnum.vote.name());
			}else if(GameStepEnum.vote == stepEnum){
				room.setStep(GameStepEnum.dark_work.name());
				room.setRound(room.getRound()+1);
			}
			roomService.updateRoundStep(room);
		}
		
		//this.messageSendBiz.sendMsgByGameRecord(gameRecord, gameRoomInfo);
		
		this.addGameSchedule(gameRoomInfo, stepEnum.getTime());
		
	}
	
	private Integer getCurrentRoomStepAgreedTarget(Room room,PlayerActionEnum action){
		StepActionRecord stepActionCondition = new StepActionRecord();
		
		stepActionCondition.setRoomId(room.getId());
		stepActionCondition.setRoundNum(room.getRound());
		stepActionCondition.setStep(room.getStep());
		stepActionCondition.setAction(action.name());
		List<StepActionRecord> stepKillAction = stepActionService.queryByCondition(stepActionCondition);
		
		Map<Integer,Integer> killTargetCountMap = Maps.newHashMap();
		for(StepActionRecord record:stepKillAction){
			Integer target = record.getTarget();
			
			Integer count = killTargetCountMap.get(target);
			if(count == null){
				count = new Integer(0);
			}
			count++;
			killTargetCountMap.put(target,count);
		}
		
		Integer target  = null;
		
		List<Map.Entry<Integer,Integer>> mappingList = new ArrayList<Map.Entry<Integer,Integer>>(killTargetCountMap.entrySet());
		if(mappingList.size() ==1){
			target = mappingList.get(0).getKey();
		}else{
			Collections.sort(mappingList, new Comparator<Map.Entry<Integer,Integer>>(){ 
				   public int compare(Map.Entry<Integer,Integer> mapping1,Map.Entry<Integer,Integer> mapping2){ 
				    return mapping2.getValue().compareTo(mapping1.getValue()); 
				   } 
				  }); 
			Integer target1Count =  mappingList.get(0).getValue();
			Integer target2Count =  mappingList.get(1).getValue();
			if(target1Count>target2Count){
				target = mappingList.get(0).getKey();
			}
		}
		
		return target;
	}
	
	private List<Map.Entry<Integer,Integer>> getCurrentRoomStepAgreedTopTarget(Room room,PlayerActionEnum action){
		StepActionRecord stepActionCondition = new StepActionRecord();
		
		stepActionCondition.setRoomId(room.getId());
		stepActionCondition.setRoundNum(room.getRound());
		stepActionCondition.setStep(room.getStep());
		stepActionCondition.setAction(action.name());
		List<StepActionRecord> stepKillAction = stepActionService.queryByCondition(stepActionCondition);
		
		Map<Integer,Integer> killTargetCountMap = Maps.newHashMap();
		for(StepActionRecord record:stepKillAction){
			Integer target = record.getTarget();
			
			Integer count = killTargetCountMap.get(target);
			if(count == null){
				count = new Integer(0);
			}
			count++;
			killTargetCountMap.put(target,count);
		}
		
		
		
		List<Map.Entry<Integer,Integer>> mappingList = new ArrayList<Map.Entry<Integer,Integer>>(killTargetCountMap.entrySet());
		Collections.sort(mappingList, new Comparator<Map.Entry<Integer,Integer>>(){ 
			   public int compare(Map.Entry<Integer,Integer> mapping1,Map.Entry<Integer,Integer> mapping2){ 
			    return mapping2.getValue().compareTo(mapping1.getValue()); 
			   } 
			  }); 
		List<Map.Entry<Integer,Integer>> finalList = Lists.newArrayList();
		Map.Entry<Integer,Integer> tempEntry = null;
		for(Map.Entry<Integer,Integer> entry:mappingList){
			if(tempEntry != null){
				if(entry.getValue()< tempEntry.getValue()){
					break;
				}	
			}
			finalList.add(entry);
			tempEntry = entry;
			
		}
		return finalList;
		
	}

}
